package com.me.collector;

import java.util.ArrayList;

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.badlogic.gdx.graphics.g2d.ParticleEffect;
import com.badlogic.gdx.graphics.g2d.ParticleEffectPool;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.g2d.ParticleEffectPool.PooledEffect;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.Joint;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.physics.box2d.joints.RevoluteJoint;
import com.badlogic.gdx.physics.box2d.joints.RevoluteJointDef;
import com.badlogic.gdx.utils.Array;
import com.me.collector.Definitions.EntityCategory;

public class Container {
	private short category = (short)EntityCategory.Container.getValue();
	private short mask = (short)((short)EntityCategory.Item.getValue());
	
	float width = 32;
	float height = 32;
	
	Texture texture;
	Sprite sprite;
	Body body;
	Joint joint;
	Sound soundCollect;
	int maxItems;
	int items;
	int score;
	
	ParticleEffectPool starEffectPool;
    Array<PooledEffect> effects;

	enum ContainerType {
		bucket, flowerpot, wok
	}

	public Container(World world, Sprite playerSprite, Body playerBody, float localXCenter) {
		// Type & Texture
		setType(world, playerSprite, playerBody, localXCenter, ContainerType.wok);
		
		// Sounds
		soundCollect = Gdx.audio.newSound(Gdx.files.internal("sounds/collect.wav"));
		
		// Particles
		effects = new Array();
		ParticleEffect dustEffect = new ParticleEffect();
		dustEffect.load(Gdx.files.internal("particles/starParticle.p"), Gdx.files.internal("particles"));
		starEffectPool = new ParticleEffectPool(dustEffect, 1, 2);
	}

	// Sets the container to a specific type
	public void setType(World world, Sprite playerSprite, Body playerBody, float localXCenter,
			ContainerType type) {
		this.dispose(world); // destroy old body and texture first

		PolygonShape shape = new PolygonShape();

		switch (type) {
		case flowerpot:
			width = 32;
			height = 32;
			maxItems = 10;
			changeTexture("container/flowerpot.png", width, height);
			shape.setAsBox(
					width * Definitions.WORLD_TO_BOX / 2f,
					height * Definitions.WORLD_TO_BOX / 2f,
					new Vector2(width * Definitions.WORLD_TO_BOX / 2f, height * Definitions.WORLD_TO_BOX / 2f),
					0);
			break;
		case bucket:
			width = 32;
			height = 32;
			maxItems = 15;
			changeTexture("container/bucket.png", width, height);
			shape.setAsBox(
					width * Definitions.WORLD_TO_BOX / 2f,
					height * Definitions.WORLD_TO_BOX / 2f,
					new Vector2(width * Definitions.WORLD_TO_BOX / 2f, height * Definitions.WORLD_TO_BOX / 2f),
					0);
			break;
		case wok:
			width = 64;
			height = 16;
			maxItems = 15;
			changeTexture("container/wok.png", width, height);
			shape.setAsBox(
					width * Definitions.WORLD_TO_BOX / 2f,
					height * Definitions.WORLD_TO_BOX / 2f, 
					new Vector2(width * Definitions.WORLD_TO_BOX / 2f, height * Definitions.WORLD_TO_BOX / 2f),
					0);
			break;
		}

		// Create Body from this shape
		BodyDef bodyDef = new BodyDef();
		bodyDef.type = BodyType.DynamicBody;
		bodyDef.position
				.set((playerSprite.getX() + localXCenter - (sprite.getWidth() / 2f))
						* Definitions.WORLD_TO_BOX,
						(playerSprite.getY() + playerSprite.getHeight())
								* Definitions.WORLD_TO_BOX);
		body = world.createBody(bodyDef);
		FixtureDef fixtureDef = new FixtureDef();
		fixtureDef.shape = shape;
		fixtureDef.density = 1f;
		fixtureDef.friction = 15f;
		fixtureDef.restitution = 0f;
		fixtureDef.filter.categoryBits = category;
		fixtureDef.filter.maskBits = mask;
		
		body.createFixture(fixtureDef);
		shape.dispose();

		// Pin the heros body and the container with a revolute joint. By doing
		// this the container should rotate a little when movement of the player
		// changes.
		
		RevoluteJointDef jointDef = new RevoluteJointDef();
		jointDef.bodyA = playerBody;
		jointDef.bodyB = body;
		jointDef.collideConnected = false;
		jointDef.localAnchorA.set(localXCenter * Definitions.WORLD_TO_BOX / 2f, playerSprite.getHeight() * Definitions.WORLD_TO_BOX);
		jointDef.localAnchorB.set(sprite.getWidth() * Definitions.WORLD_TO_BOX / 2, 0);
		jointDef.enableLimit = true;
		jointDef.lowerAngle = (float) -Math.PI / 7;
		jointDef.upperAngle = (float) Math.PI / 7;
		joint = world.createJoint(jointDef);
		
	}

	// Sets the texture (only the texture)
	private void changeTexture(String texturePath, float width, float height) {
		this.width = width;
		this.height = height;
		texture = new Texture(Gdx.files.internal(texturePath));
		sprite = new Sprite(texture);
		sprite.setSize(width, height);
		sprite.setOrigin(0, 0);
	}
	
	public void update() {
		float angle = body.getAngle();
		if(angle > Math.PI) angle -= Math.PI * 2;
		body.setAngularVelocity(- 1 * angle);
		sprite.setPosition(body.getPosition().x * Definitions.BOX_TO_WORLD, body.getPosition().y * Definitions.BOX_TO_WORLD);
		sprite.setRotation(body.getAngle() * 180 / (float)Math.PI);
		// TEST
		if(Gdx.input.isKeyPressed(Keys.A)) AddAmount(1);
	}
	
	// if hero catches an item call this method
	public void AddAmount(int amount) {
		items += amount;
		if(items > maxItems) items = maxItems;
		addCollectEffect(sprite.getX() + 0.5f * sprite.getWidth(), sprite.getY() + sprite.getHeight());
		soundCollect.play();
		System.out.println("Items: " + items + " / " + maxItems);
	}
	
	public void AddItem(Item item)
	{
		AddAmount(1);
		score += item.getScore();
	}
	
	// Creates Particle effect
	private void addCollectEffect(float x, float y) {
		PooledEffect effect = starEffectPool.obtain();
		effect.setPosition(x, y);
		effects.add(effect);
	}
	
	// draws collect particle effect
	private void drawParticles(SpriteBatch batch, float delta) {
		for (int i = effects.size - 1; i >= 0; i--) {
	        PooledEffect effect = effects.get(i);
	        effect.draw(batch, delta);
	        if (effect.isComplete()) {
	                effect.free();
	                effects.removeIndex(i);
	        }
		}
	}
	
	public void draw(SpriteBatch batch) {
		sprite.draw(batch);
		drawParticles(batch, 1 / 45f);
	}
	
	public void dispose(World world) {
		if (body != null) {
			world.destroyBody(body);
		}
		if (texture != null) {
			texture.dispose();
		}
	}
	
	public void pause()
	{
		body.setAwake(false);
	}
	
	public void resume()
	{
		body.setAwake(true);
	}
	
	// properties
	public Body getBody()
	{
		return body;
	}
}
